home *** CD-ROM | disk | FTP | other *** search
/ C/C++ Users Group Library 1996 July / C-C++ Users Group Library July 1996.iso / vol_200 / 219_01 / a48.c < prev    next >
Encoding:
C/C++ Source or Header  |  1989-01-11  |  15.1 KB  |  609 lines

  1. /*
  2.     HEADER:        CUG219;
  3.     TITLE:        8048 Cross-Assembler (Portable);
  4.     FILENAME:    A48UTIL.C;
  5.     VERSION:    0.2;
  6.     DATE:        11/09/1988;
  7.  
  8.     DESCRIPTION:    "This program lets you use your computer to assemble
  9.             code for the Intel 8048 family of microprocessors.
  10.             The program is written in portable C rather than BDS
  11.             C.  All assembler features are supported except
  12.             relocation, linkage, and macros.";
  13.  
  14.     KEYWORDS:    Software Development, Assemblers, Cross-Assemblers,
  15.             Intel, 8048;
  16.  
  17.     SYSTEM:        CP/M-80, CP/M-86, HP-UX, MSDOS, PCDOS, QNIX;
  18.     COMPILERS:    Aztec C86, Aztec CII, CI-C86, Eco-C, Eco-C88, HP-UX,
  19.             Lattice C, Microsoft C,    QNIX C;
  20.  
  21.     WARNINGS:    "This program has compiled successfully on 2 UNIX
  22.             compilers, 5 MSDOS compilers, and 2 CP/M compilers.
  23.             A port to Toolworks C is untried."
  24.  
  25.     AUTHORS:    William C. Colley III;
  26. */
  27.  
  28. /*
  29.               8048 Cross-Assembler in Portable C
  30.  
  31.         Copyright (c) 1985,1987 William C. Colley, III
  32.  
  33. Revision History:
  34.  
  35. Ver    Date        Description
  36.  
  37. 0.0    APR 1987    Adapted from version 2.4 of my portable 1805A cross-
  38.             assembler.  WCC3.
  39.  
  40. 0.1    AUG 1988    Fixed a bug in the command line parser that puts it
  41.             into a VERY long loop if the user types a command line
  42.             like "A48 FILE.ASM -L".  WCC3 per Alex Cameron.
  43.  
  44. 0.2    NOV 1988    Fixed a name conflict between a variable and a goto
  45.             label that caused some compilers to choke.  WCC3.
  46.  
  47. This file contains the main program and line assembly routines for the
  48. assembler.  The main program parses the command line, feeds the source lines
  49. to the line assembly routine, and sends the results to the listing and object
  50. file output routines.  It also coordinates the activities of everything.  The
  51. line assembly routine uses the expression analyzer and the lexical analyzer to
  52. parse the source line convert it into the object bytes that it represents.
  53. */
  54.  
  55. /*  Get global goodies:  */
  56.  
  57. #include "a48.h"
  58.  
  59. /*  Define global mailboxes for all modules:                */
  60.  
  61. char errcode, line[MAXLINE + 1], title[MAXLINE];
  62. int pass = 0;
  63. int eject, filesp, forwd, listhex;
  64. unsigned address, bytes, errors, listleft, obj[MAXLINE], pagelen, pc;
  65. FILE *filestk[FILES], *source;
  66. TOKEN token;
  67.  
  68. /*  Mainline routine.  This routine parses the command line, sets up    */
  69. /*  the assembler at the beginning of each pass, feeds the source text    */
  70. /*  to the line assembler, feeds the result to the listing and hex file    */
  71. /*  drivers, and cleans everything up at the end of the run.        */
  72.  
  73. static int done, ifsp, off;
  74.  
  75. void main(argc,argv)
  76. int argc;
  77. char **argv;
  78. {
  79.     SCRATCH unsigned *o;
  80.     int newline();
  81.     void asm_line();
  82.     void lclose(), lopen(), lputs();
  83.     void hclose(), hopen(), hputc();
  84.     void error(), fatal_error(), warning();
  85.  
  86.     printf("8048 Cross-Assembler (Portable) Ver 0.1\n");
  87.     printf("Copyright (c) 1985,1987 William C. Colley, III\n\n");
  88.  
  89.     while (--argc > 0) {
  90.     if (**++argv == '-') {
  91.         switch (toupper(*++*argv)) {
  92.         case 'L':   if (!*++*argv) {
  93.                 if (!--argc) { warning(NOLST);  break; }
  94.                 else ++argv;
  95.                 }
  96.                 lopen(*argv);
  97.                 break;
  98.  
  99.         case 'O':   if (!*++*argv) {
  100.                 if (!--argc) { warning(NOHEX);  break; }
  101.                 else ++argv;
  102.                 }
  103.                 hopen(*argv);
  104.                 break;
  105.  
  106.         default:    warning(BADOPT);
  107.         }
  108.     }
  109.     else if (filestk[0]) warning(TWOASM);
  110.     else if (!(filestk[0] = fopen(*argv,"r"))) fatal_error(ASMOPEN);
  111.     }
  112.     if (!filestk[0]) fatal_error(NOASM);
  113.  
  114.     while (++pass < 3) {
  115.     fseek(source = filestk[0],0L,0);  done = off = FALSE;
  116.     errors = filesp = ifsp = pagelen = pc = 0;  title[0] = '\0';
  117.     while (!done) {
  118.         errcode = ' ';
  119.         if (newline()) {
  120.         error('*');
  121.         strcpy(line,"\tEND\n");
  122.         done = eject = TRUE;  listhex = FALSE;
  123.         bytes = 0;
  124.         }
  125.         else asm_line();
  126.         pc = word(pc + bytes);
  127.         if (pass == 2) {
  128.         lputs();
  129.         for (o = obj; bytes--; hputc(*o++));
  130.         }
  131.     }
  132.     }
  133.  
  134.     fclose(filestk[0]);  lclose();  hclose();
  135.  
  136.     if (errors) printf("%d Error(s)\n",errors);
  137.     else printf("No Errors\n");
  138.  
  139.     exit(errors);
  140. }
  141.  
  142. /*  Line assembly routine.  This routine gets expressions and tokens    */
  143. /*  from the source file using the expression evaluator and lexical    */
  144. /*  analyzer, respectively.  It fills a buffer with the machine code    */
  145. /*  bytes and returns nothing.                        */
  146.  
  147. static char label[MAXLINE];
  148. static int ifstack[IFDEPTH] = { ON };
  149.  
  150. static OPCODE *opcod;
  151.  
  152. void asm_line()
  153. {
  154.     SCRATCH int i;
  155.     int isalph(), popc();
  156.     OPCODE *find_code(), *find_operator();
  157.     void do_label(), flush(), normal_op(), pseudo_op();
  158.     void error(), pops(), pushc(), trash();
  159.  
  160.     address = pc;  bytes = 0;  eject = forwd = listhex = FALSE;
  161.     for (i = 0; i < BIGINST; obj[i++] = NOP);
  162.  
  163.     label[0] = '\0';
  164.     if ((i = popc()) != ' ' && i != '\n') {
  165.     if (isalph(i)) {
  166.         pushc(i);  pops(label);
  167.         if (find_operator(label)) { label[0] = '\0';  error('L'); }
  168.     }
  169.     else {
  170.         error('L');
  171.         while ((i = popc()) != ' ' && i != '\n');
  172.     }
  173.     }
  174.  
  175.     trash(); opcod = NULL;
  176.     if ((i = popc()) != '\n') {
  177.     if (!isalph(i)) error('S');
  178.     else {
  179.         pushc(i);  pops(token.sval);
  180.         if (!(opcod = find_code(token.sval))) error('O');
  181.     }
  182.     if (!opcod) { listhex = TRUE;  bytes = BIGINST; }
  183.     }
  184.  
  185.     if (opcod && opcod -> attr & ISIF) { if (label[0]) error('L'); }
  186.     else if (off) { listhex = FALSE;  flush();  return; }
  187.  
  188.     if (!opcod) { do_label();  flush(); }
  189.     else {
  190.     listhex = TRUE;
  191.     if (opcod -> attr & PSEUDO) pseudo_op();
  192.     else normal_op();
  193.     while ((i = popc()) != '\n') if (i != ' ') error('T');
  194.     }
  195.     source = filestk[filesp];
  196.     return;
  197. }
  198.  
  199. static void flush()
  200. {
  201.     while (popc() != '\n');
  202. }
  203.  
  204. static void do_label()
  205. {
  206.     SCRATCH SYMBOL *l;
  207.     SYMBOL *find_symbol(), *new_symbol();
  208.     void error();
  209.  
  210.     if (label[0]) {
  211.     listhex = TRUE;
  212.     if (pass == 1) {
  213.         if (!((l = new_symbol(label)) -> attr)) {
  214.         l -> attr = FORWD + VAL;
  215.         l -> valu = pc;
  216.         }
  217.     }
  218.     else {
  219.         if (l = find_symbol(label)) {
  220.         l -> attr = VAL;
  221.         if (l -> valu != pc) error('M');
  222.         }
  223.         else error('P');
  224.     }
  225.     }
  226. }
  227.  
  228. static void normal_op()
  229. {
  230.     SCRATCH unsigned op, minreg, maxreg;
  231.     int grab_a(), grab_comma();
  232.     unsigned expr();
  233.     TOKEN *lex();
  234.     void do_label(), error(), s_error(), unlex();
  235.     static unsigned fixup_table[] = {    0x00, 0x5e, 0x7e, 0x70, 0x00,
  236.                     0x08, 0x09, 0x0a, 0x0b, 0x0c,
  237.                     0x0d, 0x0e, 0x0f, 0x00, 0x01,
  238.                     0x02, 0x39, 0x3a, 0x08, 0x09,
  239.                     0x0a, 0x0c, 0x0d, 0x0e, 0x0f,
  240.                     0x00, 0x00, 0x10, 0x00, 0x20,
  241.                     0x00, 0x00, 0x20, 0x30, 0x00,
  242.                     0x10                };
  243.  
  244.     do_label();  bytes = 1;
  245.     maxreg = ((opcod -> attr & N_TAGS) - 1) +
  246.     (minreg = (opcod -> attr & MIN_TAG) >> 4);
  247.  
  248.     switch (opcod -> attr & OPTYPE) {
  249.     case MOV:    op = lex() -> valu;
  250.             if ((token.attr & TYPE) != REG || grab_comma()) {
  251.                 s_error();  break;
  252.             }
  253.             switch (op) {
  254.                 case A:    if ((lex() -> attr & TYPE) == REG) {
  255.                         switch (op = token.valu) {
  256.                         case PSW: obj[0] = 0xc7;
  257.                               break;
  258.  
  259.                         case T:   obj[0] = 0x42;
  260.                               break;
  261.  
  262.                         default:  if (op < minreg ||
  263.                                 op > maxreg)
  264.                                 s_error();
  265.                               else
  266.                                 obj[0] = 0xf0 +
  267.                                   fixup_table[op];
  268.                               break;
  269.                         }
  270.                     }
  271.                     else if ((token.attr & TYPE) == IMM) {
  272.                         obj[0] = 0x23;  goto do_immediate;
  273.                     }
  274.                     else s_error();
  275.                     break;
  276.  
  277.                 case PSW:    if (grab_a()) s_error();
  278.                     else obj[0] = 0xd7;
  279.                     break;
  280.  
  281.                 case T:    if (grab_a()) s_error();
  282.                     else obj[0] = 0x62;
  283.                     break;
  284.  
  285.                 default:    if (op < minreg || op > maxreg)
  286.                         s_error();
  287.                     else if (grab_a()) {
  288.                         if ((token.attr & TYPE) != IMM)
  289.                         s_error();
  290.                         else {
  291.                         obj[0] = 0xb0 +
  292.                             fixup_table[op];
  293.                         goto do_immediate;
  294.                         }
  295.                     }
  296.                     else obj[0] = 0xa0 + fixup_table[op];
  297.                     break;
  298.             }
  299.             break;
  300.  
  301.     case LNG_JMP:    if ((op = expr()) > 0xfff) error('V');
  302.             else if (opcod -> valu == 0x14 &&
  303.                 (pc & 0x7fe) == 0x7fe) error('B');
  304.             else {
  305.                 obj[0] = opcod -> valu + ((op & 0x700) >> 3);
  306.                 obj[1] = low(op);
  307.             }
  308.             bytes = 2;  break;
  309.  
  310.     case REG_CND:    if ((lex() -> attr & TYPE) != REG ||
  311.                 (op = token.valu) < minreg || op > maxreg ||
  312.                 grab_comma()) {
  313.                 s_error();  break;
  314.             }
  315.             obj[0] = opcod -> valu + fixup_table[op];
  316.             goto do_conditional;
  317.  
  318.     case JMP_CND:    obj[0] = opcod -> valu;
  319. do_conditional:        if ((op = expr()) > 0xfff) error('V');
  320.             else if (((pc + 1) ^ op) & 0x700) error('B');
  321.             else obj[1] = low(op);
  322.             bytes = 2;  break;
  323.  
  324.     case LOG_OP:    if ((lex() -> attr & TYPE) == REG &&
  325.                 (op = token.valu) >= BUS && op <= P2) {
  326.                 if (grab_comma() ||
  327.                 (lex() -> attr & TYPE) != IMM) {
  328.                 s_error();  break;
  329.                 }
  330.                 else {
  331.                 obj[0] = opcod -> valu + 0x40 +
  332.                     fixup_table[op];
  333.                 goto do_immediate;
  334.                 }
  335.             }
  336.             unlex();
  337.  
  338.     case ADD_OP:    if (grab_a() || grab_comma()) {
  339.                 s_error();  break;
  340.             }
  341.             if ((lex() -> attr & TYPE) != IMM) {
  342.                 unlex();  goto one_arg;
  343.             }
  344.             if (opcod -> valu == 0x60 || opcod -> valu == 0x70)
  345.                 obj[0] = opcod -> valu - 0x5d;
  346.             else obj[0] = opcod -> valu + 0x03;
  347. do_immediate:        if ((op = expr()) > 0xff && op < 0xff80) error('V');
  348.             else obj[1] = low(op);
  349.             bytes = 2;  break;
  350.  
  351.     case A_AT_A:    if (grab_a() || grab_comma()) {
  352.                 s_error();  break;
  353.             }
  354.             goto one_arg;
  355.  
  356.     case OUTPUT:    if ((lex() -> attr & TYPE) != REG ||
  357.                 (op = token.valu) < minreg || op > maxreg ||
  358.                 grab_comma() || grab_a()) {
  359.                 s_error();  break;
  360.             }
  361.             if (!opcod -> valu) op -= 3;
  362.             goto fixup;
  363.  
  364.     case A_REG_2:    if ((lex() -> attr & TYPE) == REG &&
  365.                 (op = token.valu) >= minreg && op <= maxreg) {
  366.                 if (grab_comma() || grab_a()) s_error();
  367.                 else obj[0] = (opcod -> valu ? 0x90 : 0x30)
  368.                 + fixup_table[op];
  369.                 break;
  370.             }
  371.             unlex();
  372.  
  373. a_reg_1:
  374.     case A_REG_1:    if (grab_a() || grab_comma()) {
  375.                 s_error();  break;
  376.             }
  377.             goto one_arg;
  378.  
  379.     case INC_DEC:    if (!grab_a()) {
  380.                 obj[0] = (opcod -> valu == 0x10 ? 0x17 : 0x07);
  381.                 break;
  382.             }
  383.             unlex();
  384.  
  385. one_arg:
  386.     case ONE_ARG:    if ((lex() -> attr & TYPE) != REG ||
  387.                 (op = token.valu) < minreg || op > maxreg) {
  388.                 error ('S');  break;
  389.             }
  390. fixup:            obj[0] = opcod -> valu + fixup_table[op];  break;
  391.  
  392.     case NO_ARG:    obj[0] = opcod -> valu;  break;
  393.     }
  394.     return;
  395. }
  396.  
  397. static int grab_a()
  398. {
  399.     TOKEN *lex();
  400.  
  401.     return (lex() -> attr & TYPE) != REG || token.valu != A;
  402. }
  403.  
  404. static int grab_comma()
  405. {
  406.     TOKEN *lex();
  407.  
  408.     return (lex() -> attr & TYPE) != SEP;
  409. }
  410.  
  411. static void s_error()
  412. {
  413.     void error();
  414.  
  415.     bytes = 2;  error('S');
  416. }
  417.  
  418. static void pseudo_op()
  419. {
  420.     SCRATCH char *s;
  421.     SCRATCH unsigned *o, u;
  422.     SCRATCH SYMBOL *l;
  423.     int popc();
  424.     unsigned expr();
  425.     SYMBOL *find_symbol(), *new_symbol();
  426.     TOKEN *lex();
  427.     void do_label(), error(), fatal_error();
  428.     void hseek(), pushc(), trash(), unlex();
  429.  
  430.     o = obj;
  431.     switch (opcod -> valu) {
  432.     case DB:    do_label();
  433.             do {
  434.             if ((lex() -> attr & TYPE) == SEP) u = 0;
  435.             else {
  436.                 if (token.attr == STR) {
  437.                 trash();  pushc(u = popc());
  438.                 if (u == ',' || u == '\n') {
  439.                     for (s = token.sval; *s; *o++ = *s++)
  440.                     ++bytes;
  441.                     lex();  continue;
  442.                 }
  443.                 }
  444.                 unlex();
  445.                 if ((u = expr()) > 0xff && u < 0xff80) {
  446.                 u = 0;  error('V');
  447.                 }
  448.             }
  449.             *o++ = low(u);  ++bytes;
  450.             } while ((token.attr & TYPE) == SEP);
  451.             break;
  452.  
  453.     case DS:    do_label();  u = word(pc + expr());
  454.             if (forwd) error('P');
  455.             else {
  456.             pc = u;
  457.             if (pass == 2) hseek(pc);
  458.             }
  459.             break;
  460.  
  461.     case DW:    do_label();
  462.             do {
  463.             if ((lex() -> attr & TYPE) == SEP) u = 0;
  464.             else { unlex();  u = expr(); }
  465.             *o++ = low(u);  *o++ = high(u);
  466.             bytes += 2;
  467.             } while ((token.attr & TYPE) == SEP);
  468.             break;
  469.  
  470.     case ELSE:  listhex = FALSE;
  471.             if (ifsp) off = (ifstack[ifsp] = -ifstack[ifsp]) != ON;
  472.             else error('I');
  473.             break;
  474.  
  475.     case END:   do_label();
  476.             if (filesp) { listhex = FALSE;  error('*'); }
  477.             else {
  478.             done = eject = TRUE;
  479.             if (pass == 2 && (lex() -> attr & TYPE) != EOL) {
  480.                 unlex();  hseek(address = expr());
  481.             }
  482.             if (ifsp) error('I');
  483.             }
  484.             break;
  485.  
  486.     case ENDIF: listhex = FALSE;
  487.             if (ifsp) off = ifstack[--ifsp] != ON;
  488.             else error('I');
  489.             break;
  490.  
  491.     case EQU:   if (label[0]) {
  492.             if (pass == 1) {
  493.                 if (!((l = new_symbol(label)) -> attr)) {
  494.                 l -> attr = FORWD + VAL;  address = expr();
  495.                 if (!forwd) l -> valu = address;
  496.                 }
  497.             }
  498.             else {
  499.                 if (l = find_symbol(label)) {
  500.                 l -> attr = VAL;  address = expr();
  501.                 if (forwd) error('P');
  502.                 if (l -> valu != address) error('M');
  503.                 }
  504.                 else error('P');
  505.             }
  506.             }
  507.             else error('L');
  508.             break;
  509.  
  510.     case IF:    if (++ifsp == IFDEPTH) fatal_error(IFOFLOW);
  511.             address = expr();
  512.             if (forwd) { error('P');  address = TRUE; }
  513.             if (off) { listhex = FALSE;  ifstack[ifsp] = NULL; }
  514.             else {
  515.             ifstack[ifsp] = address ? ON : OFF;
  516.             if (!address) off = TRUE;
  517.             }
  518.             break;
  519.  
  520.     case INCL:  listhex = FALSE;  do_label();
  521.             if ((lex() -> attr & TYPE) == STR) {
  522.             if (++filesp == FILES) fatal_error(FLOFLOW);
  523.             if (!(filestk[filesp] = fopen(token.sval,"r"))) {
  524.                 --filesp;  error('V');
  525.             }
  526.             }
  527.             else error('S');
  528.             break;
  529.  
  530.     case ORG:   u = expr();
  531.             if (forwd) error('P');
  532.             else {
  533.             pc = address = u;
  534.             if (pass == 2) hseek(pc);
  535.             }
  536.             do_label();
  537.             break;
  538.  
  539.     case PAGE:  listhex = FALSE;  do_label();
  540.             if ((lex() -> attr & TYPE) != EOL) {
  541.             unlex();  pagelen = expr();
  542.             if (pagelen > 0 && pagelen < 3) {
  543.                 pagelen = 0;  error('V');
  544.             }
  545.             }
  546.             eject = TRUE;
  547.             break;
  548.  
  549.     case REGI:  if (label[0]) {
  550.             if ((lex() -> attr & TYPE) != REG || forwd ||
  551.                 (u = token.valu) < R0 || u > R7) {
  552.                 error('S');  u = R0;
  553.             }
  554.             if (pass == 1) {
  555.                 if (!((l = new_symbol(label)) -> attr)) {
  556.                 l -> attr = FORWD + REG;
  557.                 address = (l -> valu = u) - R0;
  558.                 }
  559.             }
  560.             else {
  561.                 if (l = find_symbol(label)) {
  562.                 l -> attr = REG;  address = u - R0;
  563.                 if (forwd) error('P');
  564.                 if (l -> valu != u) error('M');
  565.                 }
  566.                 else error('P');
  567.             }
  568.             }
  569.             else error('L');
  570.             break;
  571.  
  572.     case SET:   if (label[0]) {
  573.             if (pass == 1) {
  574.                 if (!((l = new_symbol(label)) -> attr)
  575.                 || (l -> attr & SOFT)) {
  576.                 l -> attr = FORWD + SOFT + VAL;
  577.                 address = expr();
  578.                 if (!forwd) l -> valu = address;
  579.                 }
  580.             }
  581.             else {
  582.                 if (l = find_symbol(label)) {
  583.                 address = expr();
  584.                 if (forwd) error('P');
  585.                 else if (l -> attr & SOFT) {
  586.                     l -> attr = SOFT + VAL;
  587.                     l -> valu = address;
  588.                 }
  589.                 else error('M');
  590.                 }
  591.                 else error('P');
  592.             }
  593.             }
  594.             else error('L');
  595.             break;
  596.  
  597.     case TITL:  listhex = FALSE;  do_label();
  598.             if ((lex() -> attr & TYPE) == EOL) title[0] = '\0';
  599.             else if ((token.attr & TYPE) != STR) error('S');
  600.             else strcpy(title,token.sval);
  601.             break;
  602.  
  603.     }
  604.     return;
  605. }
  606.   if (l = find_symbol(label)) {
  607.                 l -> attr = REG;  address = u - R0;
  608.                 if (forwd) error('P');
  609.                 if